Questions
7 of 24
1How does NestJS resolve constructor injection at runtime?
2What does @Optional() decorator do in NestJS?
3What is the difference between moduleRef.get() and moduleRef.resolve() in NestJS?
4When do you need @Inject(TOKEN) vs plain constructor injection in NestJS?
5What is ModuleRef in NestJS and when would you use it?
6What are the three provider scopes in NestJS and when is each appropriate?
7What is the correct architectural solution for circular dependencies beyond forwardRef()?
8How do you detect and debug circular dependency errors in large NestJS projects?
9What is property-based injection in NestJS and when should you use it?
10How do you write a unit test for a NestJS service that has injected dependencies?
11What is a DI token and what types can be used as tokens in NestJS?
12How do you pass a custom REQUEST object to a REQUEST-scoped provider for queues or CRON jobs in NestJS?
13How does forwardRef() solve circular dependencies in NestJS and how does it work internally?
14How do you implement the Strategy pattern using NestJS DI?
15How do you replace a provider in a NestJS test module using overrideProvider()?
16What is Inversion of Control (IoC) and how does NestJS implement it?
17What is the difference between Dependency Injection (DI) and Inversion of Control (IoC)?
18What is scope propagation in NestJS and why can it impact performance?
19How do you inject the raw HTTP request object inside a REQUEST-scoped provider in NestJS?
20How does moduleRef.resolve() work with scoped providers and what is ContextIdFactory used for?
21What role does reflect-metadata play in NestJS DI?
22What is a circular dependency in NestJS and how does it manifest at runtime?
23What is LazyModuleLoader in NestJS and how does it differ from standard DI?
24What happens to REQUEST-scoped providers during WebSocket connections or microservice message handling in NestJS?
07 / 24

What is the correct architectural solution for circular dependencies beyond forwardRef()?

forwardRef() is a patch, not a fix. Circular dependencies are a design smell signaling that two services know too much about each other. The proper solutions are: extract shared logic into a third service, use events to decouple communication, merge the two services, or redesign responsibilities to eliminate the bidirectional dependency.

Architectural solutions for circular dependencies:
  1. 1

    Extract shared logic — move mutually needed code into a third independent service that both can import without creating a cycle.

  2. 2

    Use events — have one service emit an event via NestJS EventEmitter or a message bus that the other listens to, removing the direct reference.

  3. 3

    Merge services — if two services always need each other, they may belong together as a single cohesive service.

  4. 4

    Redesign responsibilities — ask why A needs B and B needs A. Usually one direction is accidental and can be inverted or removed.

Extracting shared logic into a third service